#include "MBConversionMethods.h"
#include "MBDataTypes.h"
#include "MBDirectoryMethods.h"
#include "MBEnums.h"
#include "MBImageManager.h"
#include "MBLabelingOptions.h"
#include "MBStringMethods.h"
#include "MBTimer.h"
#include "MBTriangleLabeler.h"
#include "MBTriangleLabelerBasedProjectOptions.h"
#include "MyDistanceMap.h"

#include <iostream>
#include <set>
#include <string>
#include <vector>

using std::cout;
using std::endl;
using std::set;
using std::string;
using std::vector;

#define TEST_WITH_ADAMTEC_DATA 1
#define TEST_WITH_RIEGL_DATA 2

#define TEST_MODE TEST_WITH_ADAMTEC_DATA

int main( int argc, const char* argv[] )
{
	MBImageManager::Get().SetMaximumMemoryConsumptionInBytes( MBuint(2u * 1024u) * MBuint(1024u * 1024u) );

	// Parameters
	bool use_octree = false;
	double octree_cell_size = 0.1;
	MBuint num_iterations = 2u;
	double smooth_cost = 25.0;
	double label_cost = 0.0;
	double angle_weight = 1.0;

	MBTimer timer;

#if TEST_MODE == TEST_WITH_RIEGL_DATA

	// Riegl
	string riscan_path = "E:\\_Studium\\Praktikum-Labeling&Leveling__Michael_Birsak\\Models\\centcelles_20120327_Kuppelbilder.RiSCAN\\project.rsp";
	MBTriangleLabelerBasedProjectOptionsRiScanPro riegl_options( riscan_path, MB_RIEGL_IMAGE_TYPE_DISTORTED );
//	MBTriangleLabelerBasedProjectOptionsRiScanPro riegl_options( "D:\\Models\\centcelles_20120327_Kuppelbilder.RiSCAN\\project.rsp", MB_RIEGL_IMAGE_TYPE_DISTORTED );

	try
	{
		string riscan_inputfile = "E:\\_Studium\\Praktikum-Labeling&Leveling__Michael_Birsak\\Models\\cent_kuppel_meter\\cent_kuppel_meter_300000.obj";
		string riscan_outputfile = "E:\\_Studium\\Praktikum-Labeling&Leveling__Michael_Birsak\\Models\\cent_kuppel_meter\\Undistorted\\cent_kuppel_meter_300000_labeled.obj";
		MBTriangleLabeler labeler(
			riscan_inputfile /*"D:\\Models\\cent_kuppel_meter\\cent_kuppel_meter_300000.obj"*/, // Path of input file
			MB_MODELFORMAT_OBJ,
			riscan_outputfile /*"D:\\Models\\cent_kuppel_meter\\Undistorted\\cent_kuppel_meter_300000_labeled.obj"*/, // Path of output file, the directories must already exist!!!
			MB_MODELFORMAT_OBJ,
			riegl_options,
			use_octree,
			octree_cell_size,
			false );

		// Best Fragment
  		//bool success = labeler.CalculateBestLabeling( MBLabelingOptionsBestFragment( angle_weight, 10.0 ) );

		// Lowest Energy MRF
		bool success = labeler.CalculateBestLabeling( MBLabelingOptionsMRF( angle_weight, 100.0, MB_FILTERMODE_NEAREST_NEIGHBOR, num_iterations, smooth_cost, label_cost ) );

		// Lowest Energy MRF with Shifting in the Image Space
 		//labeler.CalculateBestLabeling( MBLabelingOptionsMRFSV( MB_FILTERMODE_NEAREST_NEIGHBOR, 2u, 25.0, 0.0, 2u, 1u  ) );

		if (success) labeler.GenerateLabeledModelFile();
	}
	catch (const MBIOException &e)
	{
		cout << e.what() << endl;
		return 0;
	}
	catch (const MBException &e)
	{
		cout << e.what() << endl;
		return 0;
	}
	
	cout << "Ready! This took " << timer.Toc() << " seconds" << endl;

#elif TEST_MODE == TEST_WITH_ADAMTEC_DATA

	// Adamtec
	const MBuint NUMBER_OF_IMAGES_PLUS_ONE = 68;
	string camera_views_to_use[NUMBER_OF_IMAGES_PLUS_ONE] =
	{   "A0EV0582.jpg",
		"A0EV0585.jpg",
		"A0EV0588.jpg",
		"A0EV0618.jpg",
		"A0EV0621.jpg",
		"A0EV0715.jpg",
		"A0EV0778.jpg",
		"A0EV0781.jpg",
		"A0EV0784.jpg",
		"A0EV0787.jpg",
		"A0EV0823.jpg",
		"A0EV0838.jpg",
		"A0EV0841.jpg",
		"A0EV0859.jpg",
		"A0EV0871.jpg",
		"A0EV0946.jpg",
		"A0EV0955.jpg",
		"A0EV0967.jpg",
		"A0EV0985.jpg",
		"A0EV1003.jpg",
		"A0EV1075.jpg",
		"A0EV1158.jpg",
		"A0EV1161.jpg",
		"A0EV1170.jpg",
		"A0EV1173.jpg",
		"A0EV1198.jpg",
		"A0EV1219.jpg",
		"A0EV1222.jpg",
		"A0EV1237.jpg",
		"A0EV1246.jpg",
		"A0EV1249.jpg",
		"A0EV6243.jpg",
		"A0EV6244.jpg",
		"A0EV6249.jpg",
		"A0EV6251.jpg",
		"A0EV6257.jpg",
		"A0EV6279.jpg",
		"A0EV6280.jpg",
		"A0EV6281.jpg",
		"A0EV6282.jpg",
		"A0EV6283.jpg",
		"A0EV6284.jpg",
		"A0EV6294.jpg",
		"A0EV6295.jpg",
		"A0EV6296.jpg",
		"A0EV6297.jpg",
		"A0EV6298.jpg",
		"A0EV6299.jpg",
		"A0EV6300.jpg",
		"A0EV6301.jpg",
		"A0EV6310.jpg",
		"A0EV6312.jpg",
		"A0EV6313.jpg",
		"A0EV6317.jpg",
		"A0EV6326.jpg",
		"A0EV6328.jpg",
		"A0EV6329.jpg",
		"A0EV6330.jpg",
		"A0EV6331.jpg",
		"A0EV6333.jpg",
		"A0EV6346.jpg",
		"A0EV6347.jpg",
		"A0EV6348.jpg",
		"A0EV6349.jpg",
		"A0EV6414.jpg",
		"A0EV6416.jpg",
		"A0EV6417.jpg",
		"" };
	vector<string> images_to_use_vector( &camera_views_to_use[0], &camera_views_to_use[NUMBER_OF_IMAGES_PLUS_ONE] );
	string imgs_path = "D:\\Models\\guter_hirte_adamtec";
	//string masks_path = "E:\\_Studium\\Praktikum-Labeling&Leveling__Michael_Birsak\\Models\\guter_hirte_adamtec\\masks";
	MBTriangleLabelerBasedProjectOptionsAdamtec adamtec_options( imgs_path );

	try
	{
		string imgs_inputfile = imgs_path + "\\guter_hirte.obj";
		string imgs_outputfile = "D:\\Models\\guter_hirte_adamtec\\Labeled";
		MBTriangleLabeler labeler(
			imgs_inputfile /*"D:\\Models\\guter_hirte_adamtec\\guter_hirte.obj"*/, // Path of input file
			MB_MODELFORMAT_OBJ,
			imgs_outputfile /*"D:\\Models\\guter_hirte_adamtec\\Undistorted\\guter_hirte_labeled.obj"*/, // Path of output file, the directories must already exist!!!
			MB_MODELFORMAT_OBJ,
			adamtec_options,
			false );

		MyDistanceMap my_distance_map( &labeler );

		// Best Fragment
  		//bool success = labeler.CalculateBestLabeling( MBLabelingOptionsBestFragment( angle_weight, 10.0 ) );

		// Lowest Energy MRF
		bool success = labeler.CalculateBestLabeling( MBLabelingOptionsMRF( angle_weight, 100.0, MB_FILTERMODE_NEAREST_NEIGHBOR, num_iterations, smooth_cost, label_cost ), &my_distance_map );

		// Lowest Energy MRF with Shifting in the Image Space
 		//labeler.CalculateBestLabeling( MBLabelingOptionsMRFSV( MB_FILTERMODE_NEAREST_NEIGHBOR, 2u, 25.0, 0.0, 2u, 1u  ) );

		if (success) labeler.GenerateLabeledModelFile( &my_distance_map );
	}
	catch (const MBIOException &e)
	{
		cout << e.what() << endl;
		return 0;
	}
	catch (const MBException &e)
	{
		cout << e.what() << endl;
		return 0;
	}
	
	cout << "Ready! This took " << timer.Toc() << " seconds" << endl;
#endif

	return 0;
}